﻿/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#ifndef MK_LOG_H
#define MK_LOG_H
#include "MkUtil/MkTypes.h"
#include "MkTime.h"
#include "MkLock.h"
#include "MkQueue.h"
#include "MkThread.h"

typedef enum
{
    LOG_DEBUG = 1,
    LOG_INFO = 2,
    LOG_WARNING = 3,
    LOG_ERROR = 4,
    LOG_MAX = 5
}MkLogLevel;

typedef enum
{
    TO_NONE = 0,
    TO_FILE = 1,
    TO_SCREEN = 2
}MkLogDst;

#define MkLogInit(key) CMkLog::GetInstance().Initialize(key)
#define MkLogInitLevel(key, dst) CMkLog::GetInstance().Initialize(key, dst)
#define MkLogChangeLevel(level) CMkLog::GetInstance().ChangeWriteLevel(level)
#define MkLogGetLevel(level) CMkLog::GetInstance().GetWriteLevel(level)
#define MkLogChangeWriteDst(Dst) CMkLog::GetInstance().ChangeWriteDst(Dst)
#define MkLogGetWriteDst(Dst) CMkLog::GetInstance().GetWriteDst(Dst)
#define MkLogGetModuleName(Name) CMkLog::GetInstance().GetModuleName(Name)
#ifdef _WIN32
#define MkLog(level, fmt, ...) CMkLog::GetInstance().WriteLog(level, __FILE__, __LINE__, fmt, __VA_ARGS__)
#define MkInfoLog(fmt, ...) CMkLog::GetInstance().WriteLog(LOG_INFO, __FILE__, __LINE__, fmt, __VA_ARGS__)
#define MkDebugLog(fmt, ...) CMkLog::GetInstance().WriteLog(LOG_DEBUG, __FILE__, __LINE__, fmt, __VA_ARGS__)
#define MkWarningLog(fmt, ...) CMkLog::GetInstance().WriteLog(LOG_WARNING, __FILE__, __LINE__, fmt, __VA_ARGS__)
#define MkErrorLog(fmt, ...) CMkLog::GetInstance().WriteLog(LOG_ERROR, __FILE__, __LINE__, fmt, __VA_ARGS__)
#define MkCheckErrorLog(ErrorCode, fmt, ...) if(NoneError != ErrorCode){CMkLog::GetInstance().WriteErrorCodeLog(LOG_ERROR, __FILE__, __LINE__, ErrorCode, fmt, __VA_ARGS__); return ErrorCode;}
#define MkCheckStringPos(nPos, fmt, ...) if(MkString::npos == nPos){CMkLog::GetInstance().WriteLog(LOG_ERROR, __FILE__, __LINE__, fmt, __VA_ARGS__); return InvalidParams;}
#define MkCheckPoint(pPoint,fmt, ...) if(!pPoint){CMkLog::GetInstance().WriteLog(LOG_ERROR, __FILE__, __LINE__, fmt, __VA_ARGS__); return nullptr; }
#define MkCheckErrorPoint(pPoint,ErrorCode,fmt, ...) if(!pPoint){CMkLog::GetInstance().WriteLog(LOG_ERROR, __FILE__, __LINE__, fmt, __VA_ARGS__); return ErrorCode;}
#else
#define MkLog(level, fmt, args...) CMkLog::GetInstance().WriteLog(level, __FILE__, __LINE__, fmt, ##args)  //linux
#define MkInfoLog(fmt, args...) CMkLog::GetInstance().WriteLog(LOG_INFO, __FILE__, __LINE__, fmt, ##args)
#define MkDebugLog(fmt, args...) CMkLog::GetInstance().WriteLog(LOG_DEBUG, __FILE__, __LINE__, fmt, ##args)
#define MkWarningLog(fmt, args...) CMkLog::GetInstance().WriteLog(LOG_WARNING, __FILE__, __LINE__, fmt, ##args)
#define MkErrorLog(fmt, args...) CMkLog::GetInstance().WriteLog(LOG_ERROR, __FILE__, __LINE__, fmt, ##args)
#define MkCheckErrorLog(ErrorCode, fmt, args...) \
    if(NoneError != ErrorCode)\
    {\
        CMkLog::GetInstance().WriteErrorCodeLog(LOG_ERROR, __FILE__, __LINE__, ErrorCode, fmt, ##args);\
        return ErrorCode;\
    }
#define MkCheckStringPos(nPos, fmt, args...) \
    if(MkString::npos == nPos)\
    {\
        CMkLog::GetInstance().WriteLog(LOG_ERROR, __FILE__, __LINE__, fmt, ##args);\
        return InvalidParams;\
    }
#define MkCheckPoint(pPoint, fmt, args...) \
    if(!pPoint)\
    {\
        CMkLog::GetInstance().WriteLog(LOG_ERROR, __FILE__, __LINE__, fmt, ##args);\
        return nullptr;\
    }
#define MkCheckErrorPoint(pPoint, ErrorCode, fmt, args...) \
    if(!pPoint)\
    {\
        CMkLog::GetInstance().WriteLog(LOG_ERROR, __FILE__, __LINE__, fmt, ##args);\
        return ErrorCode;\
    }
#endif

class MkApi CMkLog
{
public:
    CMkLog();
    ~CMkLog();

    static CMkLog &GetInstance();

    Uint32 Initialize(const MkString &strModuleName, Uint32 dst = TO_SCREEN);

    Uint32 ChangeWriteLevel(MkLogLevel Level);

    Uint32 GetWriteLevel(OUT MkLogLevel &Level);

    Uint32 ChangeWriteDst(Uint32 Dst);

    Uint32 GetWriteDst(OUT Uint32 &Dst);

    Uint32 GetModuleName(OUT MkString &strModuleName);

    Uint32 WriteLog(MkLogLevel Level, const char *FileName, int Line, const char *format, ...);

    Uint32 WriteErrorCodeLog(MkLogLevel Level, const char *FileName, int Line, Uint32 ErrorCode, const char *format, ...);
protected:
private:
    Uint32 GetstrLevel(MkLogLevel Level, OUT MkString &strLevel);
    Uint32 GetSimpleFileName(const MkString &SoureFile, MkString &SimpleFile);
    Uint32 GetLogFiles(const CMkTime& NowTime);
    Uint32 WriteLogToFile(const MkString& LogString);
    void Dolog();
private:
    MkString                    m_LogFileName;
    MkString                    m_strLogPath;
    MkString                    m_strModuleName;
    MkLogLevel                  m_WriteLevel;
    Uint32                      m_WriteDst;
    Uint32                      m_MaxSaveTime;              //default 30 days

    FILE                       *m_fpFile;
    MkMap<MkString, CMkTime>    m_MapLogFile;
    CMkTime                     m_CurDayTime;

    CMkThread                   m_LogThread;
    CMkQueue<MkString>          m_LogQueue;
    BOOL                        m_bRun;
    Uint64                      m_FileWriteSize;
    MkString                    m_CurLogFile;
    Uint32                      m_BackIndex;
};

#endif



